GD32F103学习笔记(2)

您所在的位置:网站首页 gd32f103 usb驱动 GD32F103学习笔记(2)

GD32F103学习笔记(2)

2023-06-17 11:51| 来源: 网络整理| 查看: 265

一、GD32与STM32区别 1.1 内部结构区别 1.1.1 内核

GD32采用二代的M3内核,STM32主要采用一代M3内核,下图是ARM公司的M3内核勘误表,GD使用的内核只有752419这一个BUG。

1.1.2 主频时钟 使用HSE(高速外部时钟):GD32的主频最大108M,STM32的主频最大72M 使用HSI(高速内部时钟):GD32的主频最大108M,STM32的主频最大64M

主频大意味着单片机代码运行的速度会更快,GD32的_NOP()时间比STM32更加短,所以不使用定时器做延时时要注意修改,项目中如果需要进行刷屏,开方运算,电机控制等操作,GD是一个不错的选择。

1.1.3 启动时间

GD32启动时间相同,由于GD运行稍快,需要延长上电时间配置(2ms)。

1.1.4 时序要求

GD32对时序要求严格,配置外设需要先打开时钟,否则可能导致外设无法配置成功;STM32的可以先配置再开时钟。

1.1.5 供电 GD32F STM32F 外部电压 2.6-3.6V 2.0-3.6V 内核电压 1.2V 1.8V 外部供电:GD32外部供电范围是2.6-3.6V,STM32外部供电范围是2.0-3.6V。GD32的供电范围比STM32相对要窄一点。 内核电压:GD32内核电压是1.2V,STM32内核电压是1.8V。GD的内核电压比STM32的内核电压要低,所以GD的芯片在运行的时候运行功耗更低。 1.2 内部FLASH区别 1.2.1 Flash擦除时间

GD32的Flash是自主研发的,和STM32的不一样。

GD Flash执行速度:GD32 Flash中程序执行为0等待周期。

STM32 Flash执行速度:ST系统频率不访问Flash等待时间关系:0等待周期,当0CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1; /* PCLK2 = HCLK */ RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1; /* PCLK1 = HCLK */ RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2; /* PLL configuration: PLLCLK = HSI * 27 = 108 MHz */ RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL)); RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLMULL27); /* Enable PLL */ RCC->CR |= RCC_CR_PLLON; /* Wait till PLL is ready */ while((RCC->CR & RCC_CR_PLLRDY) == 0) { } /* Select PLL as system clock source */ RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW)); RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL; /* Wait till PLL is used as system clock source */ while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08) { } } #endif

还没结束,这样的话可以实现108MHz,但会有串口波特率错误的BUG,还需要以下修改。

3.4 修改RCC文件

时钟改为108MHz后如果不修改RCC文件会导致串口不合适,需要修改 stm32f10x_rcc.c 文件。具体不懂可以参考GD的手册。

打开 stm32f10x_rcc.c,找到 RCC_GetClocksFreq() 函数

增加一段这样的代码就可以了 代码如下:

/** * @brief Returns the frequencies of different on chip clocks. * @param RCC_Clocks: pointer to a RCC_ClocksTypeDef structure which will hold * the clocks frequencies. * @note The result of this function could be not correct when using * fractional value for HSE crystal. * @retval None */ void RCC_GetClocksFreq(RCC_ClocksTypeDef* RCC_Clocks) { uint32_t tmp = 0, pllmull = 0, pllsource = 0, presc = 0; #ifdef STM32F10X_CL uint32_t prediv1source = 0, prediv1factor = 0, prediv2factor = 0, pll2mull = 0; #endif /* STM32F10X_CL */ #if defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || defined (STM32F10X_HD_VL) uint32_t prediv1factor = 0; #endif /* Get SYSCLK source -------------------------------------------------------*/ tmp = RCC->CFGR & CFGR_SWS_Mask; switch (tmp) { case 0x00: /* HSI used as system clock */ RCC_Clocks->SYSCLK_Frequency = HSI_VALUE; break; case 0x04: /* HSE used as system clock */ RCC_Clocks->SYSCLK_Frequency = HSE_VALUE; break; case 0x08: /* PLL used as system clock */ /* Get PLL clock source and multiplication factor ----------------------*/ pllmull = RCC->CFGR & CFGR_PLLMull_Mask; //倍频系数 & 0x003C0000(取18~21) pllsource = RCC->CFGR & CFGR_PLLSRC_Mask; //时钟源 #ifndef STM32F10X_CL pllmull = ( pllmull >> 18) + 2; //看手册里面寄存器描述 if (RCC->CFGR & 0x08000000) //取27位 { pllmull += 15; } if (pllsource == 0x00) {/* HSI oscillator clock divided by 2 selected as PLL clock entry */ RCC_Clocks->SYSCLK_Frequency = (HSI_VALUE >> 1) * pllmull; } else { #if defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || defined (STM32F10X_HD_VL) prediv1factor = (RCC->CFGR2 & CFGR2_PREDIV1) + 1; /* HSE oscillator clock selected as PREDIV1 clock entry */ RCC_Clocks->SYSCLK_Frequency = (HSE_VALUE / prediv1factor) * pllmull; #else /* HSE selected as PLL clock entry */ if ((RCC->CFGR & CFGR_PLLXTPRE_Mask) != (uint32_t)RESET) {/* HSE oscillator clock divided by 2 */ RCC_Clocks->SYSCLK_Frequency = (HSE_VALUE >> 1) * pllmull; } else { RCC_Clocks->SYSCLK_Frequency = HSE_VALUE * pllmull; } #endif } #else pllmull = pllmull >> 18; if (pllmull != 0x0D) { pllmull += 2; } else { /* PLL multiplication factor = PLL input clock * 6.5 */ pllmull = 13 / 2; } if (pllsource == 0x00) {/* HSI oscillator clock divided by 2 selected as PLL clock entry */ RCC_Clocks->SYSCLK_Frequency = (HSI_VALUE >> 1) * pllmull; } else {/* PREDIV1 selected as PLL clock entry */ /* Get PREDIV1 clock source and division factor */ prediv1source = RCC->CFGR2 & CFGR2_PREDIV1SRC; prediv1factor = (RCC->CFGR2 & CFGR2_PREDIV1) + 1; if (prediv1source == 0) { /* HSE oscillator clock selected as PREDIV1 clock entry */ RCC_Clocks->SYSCLK_Frequency = (HSE_VALUE / prediv1factor) * pllmull; } else {/* PLL2 clock selected as PREDIV1 clock entry */ /* Get PREDIV2 division factor and PLL2 multiplication factor */ prediv2factor = ((RCC->CFGR2 & CFGR2_PREDIV2) >> 4) + 1; pll2mull = ((RCC->CFGR2 & CFGR2_PLL2MUL) >> 8 ) + 2; RCC_Clocks->SYSCLK_Frequency = (((HSE_VALUE / prediv2factor) * pll2mull) / prediv1factor) * pllmull; } } #endif /* STM32F10X_CL */ break; default: RCC_Clocks->SYSCLK_Frequency = HSI_VALUE; break; } /* Compute HCLK, PCLK1, PCLK2 and ADCCLK clocks frequencies ----------------*/ /* Get HCLK prescaler */ tmp = RCC->CFGR & CFGR_HPRE_Set_Mask; tmp = tmp >> 4; presc = APBAHBPrescTable[tmp]; /* HCLK clock frequency */ RCC_Clocks->HCLK_Frequency = RCC_Clocks->SYSCLK_Frequency >> presc; /* Get PCLK1 prescaler */ tmp = RCC->CFGR & CFGR_PPRE1_Set_Mask; tmp = tmp >> 8; presc = APBAHBPrescTable[tmp]; /* PCLK1 clock frequency */ RCC_Clocks->PCLK1_Frequency = RCC_Clocks->HCLK_Frequency >> presc; /* Get PCLK2 prescaler */ tmp = RCC->CFGR & CFGR_PPRE2_Set_Mask; tmp = tmp >> 11; presc = APBAHBPrescTable[tmp]; /* PCLK2 clock frequency */ RCC_Clocks->PCLK2_Frequency = RCC_Clocks->HCLK_Frequency >> presc; /* Get ADCCLK prescaler */ tmp = RCC->CFGR & CFGR_ADCPRE_Set_Mask; tmp = tmp >> 14; presc = ADCPrescTable[tmp]; /* ADCCLK clock frequency */ RCC_Clocks->ADCCLK_Frequency = RCC_Clocks->PCLK2_Frequency / presc; }

原因:

STM32时钟配置寄存器

STM32的27位28位是保留的,但是GD32的是用来配合PLL倍频的。

GD32时钟配置寄存器

全局时钟配置寄存器在GD中命名时RCC_GCFGR,在STM32中命名为RCC_CFGR,关于PLL倍频系数配置PLLMF不同,红框内是先将HSE(8兆)分频为2得到4兆,然后27倍频得到108兆。

这时就得到了108兆的主频时钟 然后修改读取时钟的函数void RCC_GetClocksFreq(RCC_ClocksTypeDef* RCC_Clocks)

当发现时RCC_CFGR第27位置位了,就将倍频数从12+15 = 27。 3.5 修改代码执行速度

GD采用专利技术,提高了相同工作频率下的代码执行速度,带来了高性能的使用体验。这样一些在ST下面编写的程序如 While或者是For循环的延时, 移植到GD上面来肯定相应的延时会变短。 使用Timer定时器无影响。所以有用到这种延时方法的得根据实际情况进行一定的调整。GD的代码执行速度比ST更快,那么在应用中如果有一些判断的结构不够严谨也可能会导致问题。

案例 1: 在软件中编写了一个延时函数如下:

void delay(void) { uint8_t i; for(i = 0; i < 75; i++); }

通过实测相同的这一段代码: ST执行该函数的延时时间是 7.4us GD 执行该函数的延时时间是 5.4us 。

案例 2: 采用 IO模拟 I2C 的查应答函数的编写如下

#define SDA_Status() GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_1) void CheckACK(void) { cAcknowledge = true; if(SDA_Status()) { cAcknowledge = false; } }

ST上面执行OK ,但是在GD上面运行不正常, 其实这是由于GD的执行速度更快,ACK信号还出来,语句就已经执行完成了。建议修改代码:

#define SDA_Status() GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_1) void CheckACK(void) { uint8_t ucErrTimer = 0; cAcknowledge = true; while(SDA_Status()) { ucErrTime++; if(ucErrTime>250) { cAcknowledge = false; } } } 3.6 Flash方面

由于 GD 的 Flash 是自己的专利技术,ST 的 Flash 是第三方提供的,所以 GD 的 Flash 和 ST 的 Flash 有些许差异。GD32F10X Flash取值零等待,而 ST 需要 2 个等待周期,但 GD 的擦除和写入时间会长一点。

3.6.1 设置读保护用法

在代码中设置读保护,如果使用外部工具读保护比如JFLASH或脱机烧录器设置,可跳过此步骤。 在写完key序列后,需要读该位,确认key已生效,修改如下:

总共需要修改如下四个函数:

FLASH_Status FLASH_EraseOptionBytes(void) FLASH_Status FLASH_ProgramOptionByteData(uint32_t Address, uint8_t Data) FLASH_Status FLASH_EnableWriteProtection(uint32_t FLASH_Pages) FLASH_Status FLASH_ReadOutProtection(FunctionalState NewState) 3.6.2 修改擦出和写的超时宏定义

GD与ST在Flash的Erase和Program时间上有差异,修改如下:

3.6.3 修改分区

需求Flash大于256K注意,小于256K可以忽略这项。 与ST不同,GD的Flash存在分区的概念,前256K,CPU执行指令零等待,称code区,此范围外称为dataZ区。两者在擦写操作上没有区别,但在读操作时间上存在较大差别,code区代码取值零等待,data区执行代码有较大延迟,代码执行效率比code区慢一个数量级,因此data区通常不建议运行对实时性要求高的代码,为解决这个问题,可以使用分散加载的方法,比如把初始化代码,图片代码等放到data区。

3.7 ADC方面 ADC通道要配置成模拟输入,芯片默认是浮空输入,如果不配成模拟输入,ST的可以正常采集,GD不行 ADC时钟没有手动配置分频最大运行频率14MHz以内,ST可以正常采集,GD不行。 采样周期配置如下:RCC_ADCCLKConfig(RCC_PCLK2_Divx); ADC使能后需要加不少于20us延时,for(i=0;i


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3